1 module hip.windowing.platforms.windows; 2 import hip.windowing.input; 3 import hip.windowing.events; 4 5 6 version(UWP){} 7 else version(Windows) 8 version = WindowsNative; 9 10 version(WindowsNative) 11 { 12 import core.sys.windows.winuser; 13 import core.sys.windows.wingdi; 14 import core.sys.windows.winbase : GetModuleHandle, 15 GetLastError, 16 FormatMessage, 17 FORMAT_MESSAGE_ALLOCATE_BUFFER, 18 FORMAT_MESSAGE_FROM_SYSTEM, 19 LocalFree; 20 import core.sys.windows.windef; 21 22 alias HWND = void*; 23 alias HINSTANCE = void*; 24 package const(wchar)* winClassName = "HipremeEngine"; 25 package __gshared HDC hdc; 26 package HGLRC glContext; 27 28 pragma(lib, "opengl32"); 29 pragma(lib, "gdi32"); 30 pragma(lib, "user32"); //Can't import that to UWP 31 pragma(lib, "kernel32");//Can't import that to UWP 32 nothrow ushort LOWORD(ulong l) {return cast(ushort) l;} 33 nothrow ushort HIWORD(ulong l) {return cast(ushort) (l >>> 16);} 34 nothrow @system int GET_X_LPARAM(LPARAM lp){return cast(int)cast(short)LOWORD(lp);} 35 nothrow @system int GET_Y_LPARAM(LPARAM lp){return cast(int)cast(short)HIWORD(lp);} 36 nothrow @system uint GET_XBUTTON_WPARAM(WPARAM wp){ return cast(uint)HIWORD(wp);} 37 38 39 package extern(Windows) LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) nothrow @system 40 { 41 switch(msg) 42 { 43 case WM_CLOSE: 44 if(onWindowClosed != null) 45 onWindowClosed(); 46 DestroyWindow(hwnd); 47 break; 48 case WM_DESTROY: 49 PostQuitMessage(0); 50 ReleaseDC(hwnd, hdc); 51 break; 52 case WM_CHAR: 53 case WM_SYSCHAR: 54 if(onTextInput != null) 55 onTextInput(cast(wchar)wParam); 56 break; 57 case WM_SYSKEYDOWN: 58 case WM_KEYDOWN: 59 if(onKeyDown != null) 60 onKeyDown(cast(uint)wParam); 61 break; 62 case WM_SYSKEYUP: 63 case WM_KEYUP: 64 if(onKeyUp != null) 65 onKeyUp(cast(uint)wParam); 66 break; 67 case WM_SIZE: //Resize 68 { 69 UINT width = LOWORD(lParam); 70 UINT height = HIWORD(lParam); 71 if(onWindowResize != null) 72 onWindowResize(width, height); 73 break; 74 } 75 case WM_MOVE: 76 { 77 break; 78 } 79 case WM_MOUSEMOVE: 80 { 81 if(onMouseMove != null) 82 onMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 83 break; 84 } 85 case WM_LBUTTONDOWN: 86 if(onMouseDown != null) 87 onMouseDown(HipWindowingMouseButton.left, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 88 break; 89 case WM_MBUTTONDOWN: 90 if(onMouseDown != null) 91 onMouseDown(HipWindowingMouseButton.middle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 92 break; 93 case WM_RBUTTONDOWN: 94 if(onMouseDown != null) 95 onMouseDown(HipWindowingMouseButton.right, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 96 break; 97 case WM_XBUTTONDOWN: 98 if(onMouseDown != null) 99 onMouseDown( 100 GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? HipWindowingMouseButton.button1 : HipWindowingMouseButton.button2, 101 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) 102 ); 103 break; 104 case WM_LBUTTONUP: 105 if(onMouseUp != null) 106 onMouseUp(HipWindowingMouseButton.left, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 107 break; 108 case WM_MBUTTONUP: 109 if(onMouseUp != null) 110 onMouseUp(HipWindowingMouseButton.middle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 111 break; 112 case WM_RBUTTONUP: 113 if(onMouseUp != null) 114 onMouseUp(HipWindowingMouseButton.right, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 115 break; 116 case WM_XBUTTONUP: 117 if(onMouseUp != null) 118 onMouseUp( 119 GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? HipWindowingMouseButton.button1 : HipWindowingMouseButton.button2, 120 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) 121 ); 122 break; 123 case WM_MOUSEWHEEL: 124 if(onMouseWheel != null) 125 onMouseWheel( 126 0, cast(int)GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA 127 ); 128 break; 129 default: 130 return DefWindowProc(hwnd, msg, wParam, lParam); 131 } 132 return 0; 133 } 134 @nogc: 135 136 extern(Windows) nothrow @nogc HGLRC wglCreateContextAttribs(HDC, DWORD, HWND); 137 alias wglChoosePixelFormatARBProc = extern(Windows) nothrow @nogc BOOL function( 138 HDC hdc, const(int)* piAttribFList, const float* pfAttribIList, uint nMaxFormats, 139 int* piFormats, uint* nNumFormats); 140 141 alias wglCreateContextAttribsARBProc = extern(Windows) nothrow @nogc HGLRC function( 142 HDC hdc, HGLRC hShareContext,const int* attribList 143 ); 144 145 alias wglSwapIntervalEXTProc = extern(Windows) nothrow @nogc int function(int interval); 146 147 148 wglSwapIntervalEXTProc wglSwapIntervalEXT; 149 wglChoosePixelFormatARBProc wglChoosePixelFormatARB; 150 wglCreateContextAttribsARBProc wglCreateContextAttribsARB; 151 extern(Windows) nothrow @nogc void* wglGetProcAddress(const(char)* funcName); 152 153 154 extern(Windows) nothrow @nogc bool initializeOpenGL(int majorVersion, int minorVersion, ref void* hwnd) 155 { 156 PIXELFORMATDESCRIPTOR pfd = 157 { 158 PIXELFORMATDESCRIPTOR.sizeof, 159 1, 160 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER , // Flags 161 PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. 162 32, // Colordepth of the framebuffer. 163 0, 0, 0, 0, 0, 0, 164 0, 165 0, 166 0, 167 0, 0, 0, 0, 168 24, // Number of bits for the depthbuffer 169 8, // Number of bits for the stencilbuffer 170 0, // Number of Aux buffers in the framebuffer. 171 PFD_MAIN_PLANE, 172 0, 173 0, 0, 0 174 }; 175 int formatIndex = ChoosePixelFormat(hdc, &pfd); 176 if(formatIndex == 0) 177 { 178 MessageBox(NULL, "Could not choose pixel format!", "Error!", MB_ICONERROR | MB_OK); 179 return false; 180 } 181 if(!SetPixelFormat(hdc, formatIndex, &pfd)) 182 { 183 MessageBox(NULL, "Could not set pixel format!", "Error!", MB_ICONERROR | MB_OK); 184 return false; 185 } 186 glContext = wglCreateContext(hdc); 187 if(glContext is null) 188 { 189 MessageBox(NULL, "Could not create OpenGL Context", "Error!", MB_ICONERROR | MB_OK); 190 return false; 191 } 192 if(!wglMakeCurrent(hdc, glContext)) 193 { 194 MessageBox(NULL, "Coult not set OpenGL Context", "Error!", MB_ICONERROR | MB_OK); 195 return false; 196 } 197 if(majorVersion < 3 && minorVersion < 3) //This is not actually tested 198 { 199 if(!GetPixelFormat(hdc)) 200 { 201 MessageBox(NULL, "Could not get window pixel format!", "Error!", MB_ICONEXCLAMATION | MB_OK); 202 return false; 203 } 204 if(!DescribePixelFormat(hdc, formatIndex, pfd.sizeof, &pfd)) 205 { 206 MessageBox(NULL, "Could not get describe pixel format!", "Error!", MB_ICONEXCLAMATION | MB_OK); 207 return false; 208 } 209 if((pfd.dwFlags & PFD_SUPPORT_OPENGL) != PFD_SUPPORT_OPENGL) 210 { 211 MessageBox(NULL, "PixelFormatDescriptor does not support opengl!", "Error!", MB_ICONEXCLAMATION | MB_OK); 212 return false; 213 } 214 return true; 215 } 216 else 217 return initializeModernOpenGL(hwnd, majorVersion, minorVersion); 218 } 219 220 package bool initializeModernOpenGL(ref HWND hwnd, int majorVersion, int minorVersion) nothrow @nogc 221 { 222 //Load Function Pointers 223 wglChoosePixelFormatARB = cast(wglChoosePixelFormatARBProc)wglGetProcAddress("wglChoosePixelFormatARB"); 224 if(wglChoosePixelFormatARB is null) 225 { 226 MessageBox(NULL, "Could not load wglChoosePixelFormatARB", "Error", MB_ICONERROR | MB_OK); 227 return false; 228 } 229 wglCreateContextAttribsARB = cast(wglCreateContextAttribsARBProc)wglGetProcAddress("wglCreateContextAttribsARB"); 230 if(wglCreateContextAttribsARB is null) 231 { 232 MessageBox(NULL, "Could not load wglCreateContextAttribsARB", "Error", MB_ICONERROR | MB_OK); 233 return false; 234 } 235 wglSwapIntervalEXT = cast(wglSwapIntervalEXTProc)wglGetProcAddress("wglSwapIntervalEXT"); 236 if(wglSwapIntervalEXT is null) 237 { 238 MessageBox(NULL, "Could not load wglSwapIntervalEXT", "Error", MB_ICONERROR | MB_OK); 239 return false; 240 } 241 //Now, for the modern OpenGL 242 const int[19] attribList = 243 [ 244 WGL_DRAW_TO_WINDOW_ARB, true, 245 WGL_SUPPORT_OPENGL_ARB, true, 246 WGL_DOUBLE_BUFFER_ARB, true, 247 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, 248 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, 249 WGL_COLOR_BITS_ARB, 32, 250 WGL_DEPTH_BITS_ARB, 24, 251 WGL_STENCIL_BITS_ARB, 8, 252 WGL_ALPHA_BITS_ARB, 8, 253 0, // End 254 ]; 255 256 int pixelFormat; 257 uint numFormats; 258 259 if(!wglChoosePixelFormatARB(hdc, attribList.ptr, null, 1, &pixelFormat, &numFormats) || numFormats == 0) 260 { 261 MessageBox(NULL, "Could notchoose pixel format", "Error", MB_ICONERROR | MB_OK); 262 return false; 263 } 264 265 auto oldHwnd = hwnd; 266 HDC oldHDC = hdc; 267 HGLRC oldGLContext = glContext; 268 269 RECT rBorders; 270 GetWindowRect(hwnd, &rBorders); 271 RECT rNoBorders; 272 GetClientRect(hwnd, &rNoBorders); 273 RECT r; 274 r.left = rBorders.left*2 - rNoBorders.left; 275 r.right = rBorders.right*2 - rNoBorders.right; 276 r.top = rBorders.top*2 - rNoBorders.top; 277 r.bottom = rBorders.bottom*2 - rNoBorders.bottom; 278 //Create 279 hwnd = createWindow(r.right - r.left, r.bottom - r.top); 280 281 hdc = GetDC(hwnd); 282 283 PIXELFORMATDESCRIPTOR newPFD; 284 DescribePixelFormat(hdc, pixelFormat, newPFD.sizeof, &newPFD); 285 SetPixelFormat(hdc, pixelFormat, &newPFD); 286 287 int[7] contextAttribs = 288 [ 289 WGL_CONTEXT_MAJOR_VERSION_ARB, majorVersion, 290 WGL_CONTEXT_MINOR_VERSION_ARB, minorVersion, 291 WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 292 0 293 ]; 294 glContext = wglCreateContextAttribsARB(hdc, null, contextAttribs.ptr); 295 if(glContext is null) 296 { 297 MessageBox(null, "Could not create Modern OpenGL Context", "Error!", MB_ICONERROR | MB_OK); 298 return false; 299 } 300 wglMakeCurrent(null, null); 301 wglDeleteContext(oldGLContext); 302 ReleaseDC(oldHwnd, oldHDC); 303 DestroyWindow(oldHwnd); 304 if(!wglMakeCurrent(hdc, glContext)) 305 { 306 MessageBox(null, "Could not set Modern OpenGL Context", "Error!", MB_ICONERROR | MB_OK); 307 return false; 308 } 309 return true; 310 311 } 312 313 bool registerClass() 314 { 315 HINSTANCE hInstance = GetModuleHandle(null); 316 WNDCLASS wc; 317 //Register window class 318 319 wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; 320 wc.lpfnWndProc = &WndProc; 321 wc.cbClsExtra = 0; 322 wc.cbWndExtra = 0; 323 wc.hInstance = hInstance; //Application handle 324 wc.hIcon = LoadIcon(null, IDI_APPLICATION); //Big icon 325 wc.hCursor = LoadCursor(null, IDC_ARROW); //Cursor 326 wc.hbrBackground = cast(HBRUSH)(COLOR_WINDOW); //Background brush 327 wc.lpszMenuName = null; //Name of menu resource 328 wc.lpszClassName = winClassName; //Name to identify this class of windows 329 330 if(!RegisterClass(cast(const(WNDCLASSW)*)&wc)) 331 { 332 uint err = GetLastError(); 333 wchar* buffer; 334 uint size = FormatMessage( 335 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 336 cast(void*)null,err, 0, cast(LPWSTR)&buffer, 0, null); 337 MessageBox(NULL, buffer, "Window Registration Failed with message: ", MB_ICONEXCLAMATION | MB_OK); 338 LocalFree(buffer); 339 return false; 340 } 341 return true; 342 } 343 package HWND createWindow(int width, int height) @nogc nothrow 344 { 345 return CreateWindowEx( 346 0, 347 winClassName, 348 winClassName, //Title 349 WS_OVERLAPPEDWINDOW | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE, 350 CW_USEDEFAULT, CW_USEDEFAULT, 351 width, height, HWND_DESKTOP, null, GetModuleHandle(null), null 352 ); 353 } 354 355 extern(Windows) LRESULT openWindow(ref int width, ref int height, out HWND hwnd) 356 { 357 static bool registeredClass = false; 358 if(!registeredClass) 359 { 360 if(!registerClass()) 361 return 0; 362 } 363 hwnd = createWindow(width, height); 364 if(hwnd == null) 365 { 366 MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); 367 return 0; 368 } 369 hdc = GetDC(hwnd); 370 371 return 1; 372 } 373 374 void show(HWND hwnd) 375 { 376 ShowWindow(hwnd, SW_NORMAL); 377 UpdateWindow(hwnd); 378 } 379 380 void poll() 381 { 382 MSG msg; 383 while(PeekMessage(&msg, cast(void*)null, 0,0, PM_REMOVE)) //GetMessage may be a lot better 384 { 385 TranslateMessage(&msg); 386 DispatchMessage(&msg); 387 } 388 } 389 390 void swapBuffer() 391 { 392 SwapBuffers(hdc); 393 } 394 395 int[2] getWindowSize(HWND hwnd, ref string[] errors) 396 { 397 RECT rect; 398 GetClientRect(hwnd, &rect); 399 return [rect.right - rect.left, rect.bottom - rect.top]; 400 } 401 void setWindowName(string name, HWND hwnd, ref string[] errors) 402 { 403 SetWindowTextA(hwnd, name.ptr); 404 } 405 int[2] getWindowBorder(HWND hwnd) 406 { 407 RECT rBorders; 408 GetWindowRect(hwnd, &rBorders); 409 RECT rNoBorders; 410 GetClientRect(hwnd, &rNoBorders); 411 RECT r; 412 r.left = rBorders.left - rNoBorders.left; 413 r.right = rBorders.right - rNoBorders.right; 414 r.top = rBorders.top - rNoBorders.top; 415 r.bottom = rBorders.bottom - rNoBorders.bottom; 416 417 return[r.right - r.left, r.bottom - r.top]; 418 } 419 420 void setWindowSize(int width, int height, HWND hwnd, ref string[] errors) 421 { 422 int[2] borders = getWindowBorder(hwnd); 423 SetWindowPos(hwnd, null, 0, 0, width + borders[0], height+borders[1], SWP_NOMOVE); 424 } 425 426 void setVsyncActive(bool active, void* WindowHandle, ref string[] errors) @nogc nothrow @system 427 { 428 if(wglSwapIntervalEXT !is null) 429 { 430 wglSwapIntervalEXT(cast(int)active); 431 } 432 } 433 434 extern(Windows) bool destroy_GL_Context() 435 { 436 if(!wglMakeCurrent(hdc, null)) 437 { 438 MessageBox(NULL, "Could not detach OpenGL Context!", "Error!", MB_ICONEXCLAMATION | MB_OK); 439 return false; 440 } 441 if(!wglDeleteContext(glContext)) 442 { 443 MessageBox(NULL, "Could not delete OpenGL Context!", "Error!", MB_ICONEXCLAMATION | MB_OK); 444 return false; 445 } 446 glContext = null; 447 return true; 448 } 449 450 import hip.windowing.platforms.null_; 451 alias setFullscreen = hip.windowing.platforms.null_.setFullscreen; 452 } 453 454 455 456 enum WGL_ARB_pixel_format= 1; 457 enum WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000; 458 enum WGL_DRAW_TO_WINDOW_ARB = 0x2001; 459 enum WGL_DRAW_TO_BITMAP_ARB = 0x2002; 460 enum WGL_ACCELERATION_ARB = 0x2003; 461 enum WGL_NEED_PALETTE_ARB = 0x2004; 462 enum WGL_NEED_SYSTEM_PALETTE_ARB = 0x2005; 463 enum WGL_SWAP_LAYER_BUFFERS_ARB = 0x2006; 464 enum WGL_SWAP_METHOD_ARB = 0x2007; 465 enum WGL_NUMBER_OVERLAYS_ARB = 0x2008; 466 enum WGL_NUMBER_UNDERLAYS_ARB = 0x2009; 467 enum WGL_TRANSPARENT_ARB = 0x200A; 468 enum WGL_TRANSPARENT_RED_VALUE_ARB = 0x2037; 469 enum WGL_TRANSPARENT_GREEN_VALUE_ARB = 0x2038; 470 enum WGL_TRANSPARENT_BLUE_VALUE_ARB = 0x2039; 471 enum WGL_TRANSPARENT_ALPHA_VALUE_ARB = 0x203A; 472 enum WGL_TRANSPARENT_INDEX_VALUE_ARB = 0x203B; 473 enum WGL_SHARE_DEPTH_ARB = 0x200C; 474 enum WGL_SHARE_STENCIL_ARB = 0x200D; 475 enum WGL_SHARE_ACCUM_ARB = 0x200E; 476 enum WGL_SUPPORT_GDI_ARB = 0x200F; 477 enum WGL_SUPPORT_OPENGL_ARB = 0x2010; 478 enum WGL_DOUBLE_BUFFER_ARB = 0x2011; 479 enum WGL_STEREO_ARB = 0x2012; 480 enum WGL_PIXEL_TYPE_ARB = 0x2013; 481 enum WGL_COLOR_BITS_ARB = 0x2014; 482 enum WGL_RED_BITS_ARB = 0x2015; 483 enum WGL_RED_SHIFT_ARB = 0x2016; 484 enum WGL_GREEN_BITS_ARB = 0x2017; 485 enum WGL_GREEN_SHIFT_ARB = 0x2018; 486 enum WGL_BLUE_BITS_ARB = 0x2019; 487 enum WGL_BLUE_SHIFT_ARB = 0x201A; 488 enum WGL_ALPHA_BITS_ARB = 0x201B; 489 enum WGL_ALPHA_SHIFT_ARB = 0x201C; 490 enum WGL_ACCUM_BITS_ARB = 0x201D; 491 enum WGL_ACCUM_RED_BITS_ARB = 0x201E; 492 enum WGL_ACCUM_GREEN_BITS_ARB = 0x201F; 493 enum WGL_ACCUM_BLUE_BITS_ARB = 0x2020; 494 enum WGL_ACCUM_ALPHA_BITS_ARB = 0x2021; 495 enum WGL_DEPTH_BITS_ARB = 0x2022; 496 enum WGL_STENCIL_BITS_ARB = 0x2023; 497 enum WGL_AUX_BUFFERS_ARB = 0x2024; 498 enum WGL_NO_ACCELERATION_ARB = 0x2025; 499 enum WGL_GENERIC_ACCELERATION_ARB = 0x2026; 500 enum WGL_FULL_ACCELERATION_ARB = 0x2027; 501 enum WGL_SWAP_EXCHANGE_ARB = 0x2028; 502 enum WGL_SWAP_COPY_ARB = 0x2029; 503 enum WGL_SWAP_UNDEFINED_ARB = 0x202A; 504 enum WGL_TYPE_RGBA_ARB = 0x202B; 505 enum WGL_TYPE_COLORINDEX_ARB = 0x202C; 506 507 508 enum WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091; 509 enum WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092; 510 enum WGL_CONTEXT_LAYER_PLANE_ARB = 0x2093; 511 enum WGL_CONTEXT_FLAGS_ARB = 0x2094; 512 enum WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126; 513 514 515 enum WGL_CONTEXT_DEBUG_BIT_ARB = 0x0001; 516 enum WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x0002; 517 518 enum WGL_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001; 519 enum WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002; 520 521 522 enum ERROR_INVALID_VERSION_ARB = 0x2095; 523 enum ERROR_INVALID_PROFILE_ARB = 0x2096;